﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Shapes;
using X.Infrastructure.Shapes;
using X.Infrastructure.WPF.Extends;
using X.WPF.Controls.Enums;
using X.WPF.Controls.EventArgs.CanvasShapeArgs;
using X.WPF.Controls.EventArgs.DraggableControlArgs;

namespace X.WPF.Controls.CustomControls
{
    /// <summary>
    /// 画布圆形控件
    /// </summary>
    public class CanvasCircle : CanvasShape
    {
        #region # 字段及构造器

        /// <summary>
        /// 圆心
        /// </summary>
        private PointX _center;

        /// <summary>
        /// 圆心横线
        /// </summary>
        private Line _centerHorizontalLine;

        /// <summary>
        /// 圆心竖线
        /// </summary>
        private Line _centerVerticalLine;

        /// <summary>
        /// 静态构造器
        /// </summary>
        static CanvasCircle()
        {
            //注册依赖属性
            CanvasCircle.RadiusProperty = DependencyProperty.Register(nameof(CanvasCircle.Radius), typeof(double), typeof(CanvasCircle), new PropertyMetadata(0d));
            CanvasCircle.XProperty = DependencyProperty.Register(nameof(CanvasCircle.X), typeof(double), typeof(CanvasCircle), new PropertyMetadata(0d));
            CanvasCircle.YProperty = DependencyProperty.Register(nameof(CanvasCircle.Y), typeof(double), typeof(CanvasCircle), new PropertyMetadata(0d));

        }

        /// <summary>
        /// 默认构造器
        /// </summary>
        public CanvasCircle()
        : base(CanvasShapeType.Circle)
        {
        }

        #endregion

        #region # 属性

        #region 半径 —— double Radius

        /// <summary>
        /// 半径依赖属性
        /// </summary>
        public static DependencyProperty RadiusProperty;

        /// <summary>
        /// 半径
        /// </summary>
        public double Radius
        {
            get => (double)base.GetValue(CanvasCircle.RadiusProperty);
            set => base.SetValue(CanvasCircle.RadiusProperty, value);
        }

        #endregion

        #region X —— double X

        /// <summary>
        /// X依赖属性
        /// </summary>
        public static DependencyProperty XProperty;

        /// <summary>
        /// X
        /// </summary>
        public double X
        {
            get => (double)base.GetValue(CanvasCircle.XProperty);
            set => base.SetValue(CanvasCircle.XProperty, value);
        }

        #endregion

        #region Y —— double Y

        /// <summary>
        /// Y依赖属性
        /// </summary>
        public static DependencyProperty YProperty;

        /// <summary>
        /// Y
        /// </summary>
        public double Y
        {
            get => (double)base.GetValue(CanvasCircle.YProperty);
            set => base.SetValue(CanvasCircle.YProperty, value);
        }

        #endregion

        #endregion

        #region # 依赖属性 

        #endregion

        #region # 路由事件

        #endregion

        #region # 事件处理程序

        #region 画布鼠标移动事件 —— void OnCanvasMouseMove(object sender...
        /// <summary>
        /// 画布鼠标移动事件
        /// </summary>
        private void OnCanvasMouseMove(object sender, MouseEventArgs eventArgs)
        {
            if (this._parentCanvas == null)
                return;

            PointX position = eventArgs.GetPosition(this._parentCanvas).ToPointX();
            this.Render(position);
        }
        #endregion

        #region 画布鼠标松开事件 —— void OnCanvasMouseUp(object sender...
        /// <summary>
        /// 画布鼠标松开事件
        /// </summary>
        private void OnCanvasMouseUp(object sender, MouseButtonEventArgs eventArgs)
        {
            if (this._parentCanvas == null)
                return;

            PointX position = eventArgs.GetPosition(this._parentCanvas).ToPointX();
            bool result = this.Render(position);

            this._parentCanvas.MouseMove -= this.OnCanvasMouseMove;
            this._parentCanvas.MouseUp -= this.OnCanvasMouseUp;

            if (result)
            {
                CanvasShapeElementDrawnEventArgs areArgs = new CanvasShapeElementDrawnEventArgs(CanvasShape._ShapeDrawnEvent, this, this);
                this.RaiseEvent(areArgs);

                if (!areArgs.IsCancel)
                    return;

                this.DrawCancel();
            }
            else
            {
                this._parentCanvas.Children.Remove(this);
                this.RaiseEvent(new CanvasShapeElementDrawCancelEventArgs(CanvasShape._ShapeDrawCancelEvent, this, this));
            }

        }
        #endregion

        #region 圆形鼠标按下事件 —— void OnCircleMouseDown(object sender, MouseEventArgs eventArgs)
        /// <summary>
        /// 圆形鼠标按下事件
        /// </summary>
        private void OnCircleMouseDown(object sender, MouseEventArgs eventArgs)
        {
            // 挂起路由事件
            this.RaiseEvent(new CanvasShapeElementClickEventArgs(CanvasShape._ShapeClickEvent, this, null, this));
        }
        #endregion

        #endregion

        #region # 回调方法

        #region X改变回调方法 —— static void OnXChanged(DependencyObject dependencyObject...
        /// <summary>
        /// X改变回调方法
        /// </summary>
        private static void OnXChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            CanvasCircle canvasCircle = (CanvasCircle)dependencyObject;
            double x = (double)eventArgs.NewValue;
        }
        #endregion

        #region Y改变回调方法 —— static void OnYChanged(DependencyObject dependencyObject...
        /// <summary>
        /// Y改变回调方法
        /// </summary>
        private static void OnYChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            CanvasCircle canvasCircle = (CanvasCircle)dependencyObject;
            double y = (double)eventArgs.NewValue;
        }
        #endregion

        #region 半径改变回调方法 —— static void OnRadiusChanged(DependencyObject dependencyObject...
        /// <summary>
        /// 半径改变回调方法
        /// </summary>
        private static void OnRadiusChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            CanvasCircle canvasCircle = (CanvasCircle)dependencyObject;
            double radius = (double)eventArgs.NewValue;
        }
        #endregion

        #endregion

        #region # 方法

        // Override

        #region 绘制 —— override void Draw(PointX startPoint)
        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="startPoint">起点</param>
        public override void Draw(PointX startPoint)
        {
            if (this._parentCanvas == null)
                return;

            this._parentCanvas.MouseMove += this.OnCanvasMouseMove;
            this._parentCanvas.MouseUp += this.OnCanvasMouseUp;
            this._center = startPoint;
        }
        #endregion

        #region 绘制 —— override void Draw(double scale, ShapeX shapeX)
        /// <summary>
        /// 绘制
        /// </summary>
        public override void Draw(double scale, ShapeX shapeX)
        {
            CircleX circleX = (CircleX)shapeX;

            double x = circleX.X * scale;
            double y = circleX.Y * scale;
            double radius = circleX.Radius * scale;

            this.Name = circleX.Name;
            this.Tag = circleX.Tag;
            this._center = new PointX(x, y);

            this.Render(radius);
        }
        #endregion

        #region 绘制取消 —— abstract void DrawCancel()
        /// <summary>
        /// 绘制取消
        /// </summary> 
        public override void DrawCancel()
        {
            this._parentCanvas?.Children.Remove(this._centerHorizontalLine);
            this._parentCanvas?.Children.Remove(this._centerVerticalLine);

            base.DrawCancel();
        }
        #endregion

        #region 拖拽 —— override void Drag(DraggedEventArgs draggedEventArgs)
        /// <summary>
        /// 拖拽
        /// </summary> 
        /// <param name="draggedEventArgs">拖拽参数</param>
        public override void Drag(DraggedEventArgs draggedEventArgs)
        {



            //double actualX = draggedEventArgs.DragMode == DragMode.Resize ? oldCircleX.X : draggedEventArgs.NewBound.TopLeft.X;
            //double actualY = draggedEventArgs.DragMode == DragMode.Resize ? oldCircleX.Y : draggedEventArgs.NewBound.TopLeft.Y;
            //bool resizeWidth = Math.Abs(draggedEventArgs.OldBound.Width - draggedEventArgs.NewBound.Width) > 0;
            //double visualDiameter = resizeWidth ? draggedEventArgs.NewBound.Width : draggedEventArgs.NewBound.Height;
            //double visualRadius = visualDiameter;
            //double actualRadius = visualRadius / 2;
            //double centerX = draggedEventArgs.DragMode == DragMode.Resize ? actualX : (int)Math.Round((double)(actualX + actualRadius));
            //double centerY = draggedEventArgs.DragMode == DragMode.Resize ? actualY : (int)Math.Round((double)(actualY + actualRadius));

            double actualX = 0;
            double actualY = 0;
            double radius = 0;

            // 设置圆
            if (draggedEventArgs.DragMode == DragMode.Resize)
            {
                double widthChangeValue = Math.Abs(draggedEventArgs.OldBound.Width - draggedEventArgs.NewBound.Width);
                double heightChangeValue = Math.Abs(draggedEventArgs.OldBound.Height - draggedEventArgs.NewBound.Height);
                double size = widthChangeValue > heightChangeValue ? draggedEventArgs.NewBound.Width : draggedEventArgs.NewBound.Height;
                radius = size / 2;
                actualX = this.X - radius;
                actualY = this.Y - radius;

                this.ShapeElement.SetValue(Ellipse.WidthProperty, size);
                this.ShapeElement.SetValue(Ellipse.HeightProperty, size);
                Canvas.SetLeft(this.ShapeElement, actualX);
                Canvas.SetTop(this.ShapeElement, actualY);

                this.Radius = radius;
                this.Width = this.ShapeElement.Width;
                this.Height = this.ShapeElement.Height;
            }
            else
            {
                this.X = draggedEventArgs.NewBound.TopLeft.X + this.Radius;
                this.Y = draggedEventArgs.NewBound.TopLeft.Y + this.Radius;
                this._center = new PointX(this.X, this.Y);

                // 渲染圆心
                this.ReaderCenter();
            }
        }
        #endregion

        #region 初始化形状控件 —— void InitShapeElement()
        /// <summary>
        /// 初始化形状控件
        /// </summary>
        protected override Shape InitShapeElement()
        {
            Ellipse circle = new Ellipse();
            circle.MouseDown += this.OnCircleMouseDown;

            // 绑定X
            Binding xBinding = new Binding(nameof(this.Radius))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            //circle.SetBinding(Ellipse.WidthProperty, xBinding);

            return circle;
        }
        #endregion


        // Private

        #region 渲染 —— bool Render(PointX position)
        /// <summary>
        /// 渲染
        /// </summary>
        /// <param name="position">位置</param>
        private bool Render(PointX position)
        {
            VectorX vector = position - this._center;
            double radius = vector.Length;

            return this.Render(radius);
        }
        #endregion

        #region 渲染 —— bool Render(double radius)
        /// <summary>
        /// 渲染
        /// </summary>
        /// <param name="radius">半径</param>
        private bool Render(double radius)
        {


            if (!this._parentCanvas.Children.Contains(this.ShapeElement))
                this._parentCanvas.Children.Add(this.ShapeElement);

            // 渲染圆心
            if (this._parentCanvas != null && this._centerHorizontalLine == null)
                this.ReaderCenter();

            // 设置圆
            this.ShapeElement.SetValue(Ellipse.WidthProperty, radius * 2);
            this.ShapeElement.SetValue(Ellipse.HeightProperty, radius * 2);
            Canvas.SetLeft(this.ShapeElement, this._center.X - radius);
            Canvas.SetTop(this.ShapeElement, this._center.Y - radius);
            Panel.SetZIndex(this.ShapeElement, this.ZIndex);

            this.X = this._center.X;
            this.Y = this._center.Y;
            this.Radius = radius;
            this.Width = this.ShapeElement.Width;
            this.Height = this.ShapeElement.Height;

            return true;
        }
        #endregion

        #region 渲染圆心 —— void ReaderCenter()
        /// <summary>
        /// 渲染圆心
        /// </summary>
        private void ReaderCenter()
        {
            if (this._parentCanvas == null)
                return;

            if (this._centerHorizontalLine != null)
            {
                this._parentCanvas.Children.Remove(this._centerHorizontalLine);
                this._parentCanvas.Children.Remove(this._centerVerticalLine);
            }

            int lineLength = 3;

            this._centerHorizontalLine = this.ReaderCenterLine("HorizontalLine", this._center.X - lineLength, this._center.Y, this._center.X + lineLength, this._center.Y, this.ZIndex - 1);
            this._centerVerticalLine = this.ReaderCenterLine("VerticalLine", this._center.X, this._center.Y - lineLength, this._center.X, this._center.Y + lineLength, this.ZIndex - 1);

        }
        #endregion

        #region 渲染圆心线 —— Line ReaderCenterLine()
        /// <summary>
        /// 渲染圆心线
        /// </summary>
        private Line ReaderCenterLine(string name, double x1, double y1, double x2, double y2, int zindex)
        {
            Line line = new Line
            {
                Name = $"{this.Name}{name}",
                X1 = x1,
                Y1 = y1,
                X2 = x2,
                Y2 = y2,
                StrokeThickness = this.StrokeThickness,
                Fill = this.Fill,
                Stroke = this.Stroke
            };

            Binding fillBinding = new Binding(nameof(this.Fill))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            line.SetBinding(Shape.FillProperty, fillBinding);

            Binding strokeBinding = new Binding(nameof(this.Stroke))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            line.SetBinding(Shape.StrokeProperty, strokeBinding);

            this._parentCanvas.Children.Add(line);
            Panel.SetZIndex(line, zindex);

            return line;
        }
        #endregion

        #endregion
    }
}